﻿using System;
using System.Collections.Generic;
using System.Xml;

namespace ZCConsole
{
    public enum LogicSection
    {
        Left,
        Right
    }

    public enum TrainOccupy
    {
        LeftOccupy,
        RightOccupy,
        AllOccupy,
        NonOccupy
    }

    public class Section : Device, IOccupy
    {
        /// <summary>
        /// 默认方向
        /// </summary>
        public enum DefaultDirection : byte
        {
            Upward = 0xaa,     // 上行
            Downward = 0x55    // 下行
        }

        public int Direction { get; set; }

        /// <summary>
        /// 逻辑区段个数
        /// </summary>
        public int LogicCount { get; private set; }

        /// <summary>
        /// 公里标长度
        /// </summary>
        public double Distance { get; private set; }

        /// <summary>
        /// 默认方向
        /// </summary>
        public DefaultDirection DefDirection { get; set; }

        public bool IsAccessLock;

        private PSDoor relayPSDoor_;

        public PSDoor RelayPSDoor
        {
            get { return relayPSDoor_; }
            set { relayPSDoor_ = value; }
        }


        private bool axleOccpy_ = true;
        public bool AxleOccupy
        {
            get { return axleOccpy_; }
            set
            {
                if (axleOccpy_ != value)
                {
                    axleOccpy_ = value;
                }
            }
        }

        List<UInt16> hasNonComTrain_ = new List<UInt16>();
        public List<UInt16> HasNonComTrain
        {
            get { return hasNonComTrain_; }
            set
            {
                if (hasNonComTrain_ != value)
                {
                    hasNonComTrain_ = value;
                }
            }
        }

        List<UInt16> isFrontLogicOccupy_ = new List<UInt16>();
        public List<UInt16> IsFrontLogicOccupy
        {
            get { return isFrontLogicOccupy_; }
        }

        List<UInt16> isLastLogicOccupy_ = new List<UInt16>();
        public List<UInt16> IsLastLogicOccupy
        {
            get { return isLastLogicOccupy_; }
        }

        List<UInt16> isFrontRouteOpen_ = new List<UInt16>();
        public List<UInt16> IsFrontRouteOpen
        {
            get { return isFrontRouteOpen_; }
        }

        List<UInt16> isLastRouteOpen_ = new List<UInt16>();
        public List<UInt16> IsLastRouteOpen
        {
            get { return isLastRouteOpen_; }
        }

        public override void LoadData(XmlElement element)
        {
            base.LoadData(element);

            LogicCount = int.Parse(element.GetAttribute("LogicCount"));
            Distance = int.Parse(element.GetAttribute("Distance"));
            DefDirection = (DefaultDirection)Enum.Parse(
                typeof(DefaultDirection), element.GetAttribute("Direction"));
        }


        public bool GetIsEB(ZC zc)
        {
            if (this.LogicCount == 2)
            {
                return false;
            }
            else
            {
                PSDoor psdoor = Load.FindDoor.FindRelayPSDoor(this, zc);
                if (psdoor != null)
                {
                    return psdoor.IsEB;
                }
                else
                {
                    return false;
                }
            }
        }

        public bool GetIsDoorOpen(ZC zc)
        {
            if (this.LogicCount == 2)
            {
                return false;
            }
            else
            {
                PSDoor psdoor = Load.FindDoor.FindRelayPSDoor(this, zc);
                if (psdoor != null)
                {
                    return psdoor.IsOpen;
                }
                else
                {
                    return false;
                }
            }
        }

        public TrainOccupy GetTrainOccupy()
        {
            if (this.LogicCount == 1)
            {
                if (isFrontLogicOccupy_.Count == 0)
                {
                    return TrainOccupy.NonOccupy;
                }
                else
                {
                    return TrainOccupy.AllOccupy;
                }
            }
            else
            {
                if (isFrontLogicOccupy_.Count == 0 && isLastLogicOccupy_.Count == 0)
                {
                    return TrainOccupy.NonOccupy;
                }
                else if (isFrontLogicOccupy_.Count != 0 && isLastLogicOccupy_.Count == 0)
                {
                    return TrainOccupy.LeftOccupy;
                }
                else if (isFrontLogicOccupy_.Count == 0 && isLastLogicOccupy_.Count != 0)
                {
                    return TrainOccupy.RightOccupy;
                }
                else
                {
                    return TrainOccupy.AllOccupy;
                }
            }
        }

        /// <summary>
        /// 根据列车方向设置列车是否占用
        /// </summary>
        /// <param name="trainDir"></param>
        /// <param name="offset"></param>
        /// <param name="isOccupy"></param>
        /// <param name="trainID"></param>
        public void SetTrainOccupy(TrainDir trainDir, UInt32 offset, bool isOccupy, UInt16 trainID)
        {
            if (this.LogicCount == 1)
            {
                SetTrainList(this.isFrontLogicOccupy_, isOccupy, trainID);
                SetTrainList(this.isLastLogicOccupy_, isOccupy, trainID);
            }
            else
            {
                if (trainDir == TrainDir.Right)
                {
                    if (offset < (this.Distance / 2))
                    {
                        SetTrainList(this.isFrontLogicOccupy_, isOccupy, trainID);
                    }
                    else
                    {
                        SetTrainList(this.isLastLogicOccupy_, isOccupy, trainID);
                    }
                }
                else if (trainDir == TrainDir.Left)
                {
                    if (offset < (this.Distance / 2))
                    {
                        SetTrainList(this.isLastLogicOccupy_, isOccupy, trainID);
                    }
                    else
                    {
                        SetTrainList(this.isFrontLogicOccupy_, isOccupy, trainID);
                    }
                }
            }
        }

        public TrainOccupy GetTrainOccupy(UInt16 trainID)
        {
            if (this.LogicCount == 1)
            {
                if (!HasOtherTrain(isFrontLogicOccupy_, trainID))
                {
                    return TrainOccupy.NonOccupy;
                }
                else
                {
                    return TrainOccupy.AllOccupy;
                }
            }
            else
            {
                if (!HasOtherTrain(isFrontLogicOccupy_, trainID) && !HasOtherTrain(isLastLogicOccupy_, trainID))
                {
                    return TrainOccupy.NonOccupy;
                }
                else if (HasOtherTrain(isFrontLogicOccupy_, trainID) && !HasOtherTrain(isLastLogicOccupy_, trainID))
                {
                    return TrainOccupy.LeftOccupy;
                }
                else if (!HasOtherTrain(isFrontLogicOccupy_, trainID) && HasOtherTrain(isLastLogicOccupy_, trainID))
                {
                    return TrainOccupy.RightOccupy;
                }
                else
                {
                    return TrainOccupy.AllOccupy;
                }
            }
        }
        private bool HasOtherTrain(List<UInt16> list, UInt16 trainID)
        {
            if (list.Count == 0)
            {
                return false;
            }
            else if (list.Count == 1 && list.Contains(trainID))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public UInt16 GetOffset(TrainDir Direction, UInt16 trainID)
        {
            if (this.LogicCount == 1)
            {
                return Convert.ToUInt16(this.Distance);
            }
            switch (Direction)
            {
                case TrainDir.Right:
                    switch (GetTrainOccupy(trainID))
                    {
                        case TrainOccupy.NonOccupy:
                            return Convert.ToUInt16(this.Distance);
                        case TrainOccupy.RightOccupy:
                            return Convert.ToUInt16(this.Distance / 2);
                        default:
                            return 0;
                    }
                case TrainDir.Left:
                    switch (GetTrainOccupy(trainID))
                    {
                        case TrainOccupy.NonOccupy:
                            return Convert.ToUInt16(this.Distance);
                        case TrainOccupy.LeftOccupy:
                            return Convert.ToUInt16(this.Distance / 2);
                        default:
                            return 0;
                    }
                default:
                    return 0;
            }
        }

        public void SetNonCommunicateTrain(UInt16 trainID, bool isNonCom)
        {
            SetTrainList(hasNonComTrain_, isNonCom, trainID);
        }

        /// <summary>
        /// 将占用的列车ID存入列表中以及将非占用车移出列表
        /// </summary>
        /// <param name="trainList"></param>
        /// <param name="isOccupy"></param>
        /// <param name="trainID"></param>
        private void SetTrainList(List<UInt16> trainList, bool isOccupy, UInt16 trainID)
        {
            if (isOccupy)
            {
                if (!trainList.Contains(trainID))
                {
                    trainList.Add(trainID);
                }
            }
            else
            {
                if (trainList.Contains(trainID))
                {
                    trainList.Remove(trainID);
                }
            }
        }

        public void SetRouteOpen(UInt16 trainID, bool isOpen, LogicSection logicSection)
        {
            if (logicSection == LogicSection.Left)
            {
                SetTrainList(this.isFrontRouteOpen_, isOpen, trainID);
            }
            else if (logicSection == LogicSection.Right)
            {
                SetTrainList(this.isLastRouteOpen_, isOpen, trainID);
            }
        }


    }
}
